home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / mg2a_src.zip / ECHO.C < prev    next >
C/C++ Source or Header  |  1991-02-26  |  12KB  |  592 lines

  1. /*
  2.  *        Echo line reading and writing.
  3.  *
  4.  * Common routines for reading
  5.  * and writing characters in the echo line area
  6.  * of the display screen. Used by the entire
  7.  * known universe.
  8.  */
  9. /*
  10.  * The varargs lint directive comments are 0 an attempt to get lint to shup
  11.  * up about CORRECT usage of varargs.h.  It won't.
  12.  */
  13. #include    "def.h"
  14. #include    "key.h"
  15. #ifdef    LOCAL_VARARGS
  16. #include    "varargs.h"
  17. #else
  18. #include    <varargs.h>
  19. #endif
  20. #ifndef NO_MACRO
  21. #  include    "macro.h"
  22. #endif
  23.  
  24. static int    veread();
  25. VOID        ewprintf();
  26. static VOID    eformat();
  27. static VOID    eputi();
  28. static VOID    eputl();
  29. static VOID    eputs();
  30. static VOID    eputc();
  31. static int    complt();
  32.  
  33. int    epresf    = FALSE;        /* Stuff in echo line flag.    */
  34. /*
  35.  * Erase the echo line.
  36.  */
  37. VOID
  38. eerase() {
  39.     ttcolor(CTEXT);
  40.     ttmove(nrow-1, 0);
  41.     tteeol();
  42.     ttflush();
  43.     epresf = FALSE;
  44. }
  45.  
  46. /*
  47.  * Ask "yes" or "no" question.
  48.  * Return ABORT if the user answers the question
  49.  * with the abort ("^G") character. Return FALSE
  50.  * for "no" and TRUE for "yes". No formatting
  51.  * services are available. No newline required.
  52.  */
  53. eyorn(sp) char *sp; {
  54.     register int    s;
  55.  
  56. #ifndef NO_MACRO
  57.     if(inmacro) return TRUE;
  58. #endif
  59.     ewprintf("%s? (y or n) ", sp);
  60.     for (;;) {
  61.         s = getkey(FALSE);
  62.         if (s == 'y' || s == 'Y') return TRUE;
  63.         if (s == 'n' || s == 'N') return FALSE;
  64.         if (s == CCHR('G')) return ctrlg(FFRAND, 1);
  65.         ewprintf("Please answer y or n.  %s? (y or n) ", sp);
  66.     }
  67.     /*NOTREACHED*/
  68. }
  69.  
  70. /*
  71.  * Like eyorn, but for more important question. User must type either all of
  72.  * "yes" or "no", and the trainling newline.
  73.  */
  74. eyesno(sp) char *sp; {
  75.     register int    s;
  76.     char        buf[64];
  77.  
  78. #ifndef NO_MACRO
  79.     if(inmacro) return TRUE;
  80. #endif
  81.     s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp);
  82.     for (;;) {
  83.         if (s == ABORT) return ABORT;
  84.         if (s != FALSE) {
  85. #ifndef NO_MACRO
  86.             if (macrodef) {
  87.                 LINE *lp = maclcur;
  88.  
  89.                 maclcur = lp->l_bp;
  90.                 maclcur->l_fp = lp->l_fp;
  91.                 free((char *)lp);
  92.             }
  93. #endif
  94.             if ((buf[0] == 'y' || buf[0] == 'Y')
  95.                 &&    (buf[1] == 'e' || buf[1] == 'E')
  96.                 &&    (buf[2] == 's' || buf[2] == 'S')
  97.                 &&    (buf[3] == '\0')) return TRUE;
  98.             if ((buf[0] == 'n' || buf[0] == 'N')
  99.                 &&    (buf[1] == 'o' || buf[0] == 'O')
  100.                 &&    (buf[2] == '\0')) return FALSE;
  101.         }
  102.         s = ereply("Please answer yes or no.  %s? (yes or no) ",
  103.                buf, sizeof(buf), sp);
  104.     }
  105.     /*NOTREACHED*/
  106. }
  107. /*
  108.  * Write out a prompt, and read back a
  109.  * reply. The prompt is now written out with full "ewprintf"
  110.  * formatting, although the arguments are in a rather strange
  111.  * place. This is always a new message, there is no auto
  112.  * completion, and the return is echoed as such.
  113.  */
  114. /*VARARGS 0*/
  115. ereply(va_alist)
  116. va_dcl
  117. {
  118.     va_list pvar;
  119.     register char *fp, *buf;
  120.     register int nbuf;
  121.     register int i;
  122.  
  123.     va_start(pvar);
  124.     fp = va_arg(pvar, char *);
  125.     buf = va_arg(pvar, char *);
  126.     nbuf = va_arg(pvar, int);
  127.     i = veread(fp, buf, nbuf, EFNEW|EFCR, &pvar);
  128.     va_end(pvar);
  129.     return i;
  130. }
  131.  
  132. /*
  133.  * This is the general "read input from the
  134.  * echo line" routine. The basic idea is that the prompt
  135.  * string "prompt" is written to the echo line, and a one
  136.  * line reply is read back into the supplied "buf" (with
  137.  * maximum length "len"). The "flag" contains EFNEW (a
  138.  * new prompt), an EFFUNC (autocomplete), or EFCR (echo
  139.  * the carriage return as CR).
  140.  */
  141. /* VARARGS 0 */
  142. eread(va_alist)
  143. va_dcl
  144. {
  145.     va_list pvar;
  146.     char *fp, *buf;
  147.     int nbuf, flag, i;
  148.     va_start(pvar);
  149.     fp   = va_arg(pvar, char *);
  150.     buf  = va_arg(pvar, char *);
  151.     nbuf = va_arg(pvar, int);
  152.     flag = va_arg(pvar, int);
  153.     i = veread(fp, buf, nbuf, flag, &pvar);
  154.     va_end(pvar);
  155.     return i;
  156. }
  157.  
  158. static veread(fp, buf, nbuf, flag, ap) char *fp; char *buf; va_list *ap; {
  159.     register int    cpos;
  160.     register int    i;
  161.     register int    c;
  162.  
  163. #ifndef NO_MACRO
  164.     if(inmacro) {
  165.         bcopy(maclcur->l_text, buf, maclcur->l_used);
  166.         buf[maclcur->l_used] = '\0';
  167.         maclcur = maclcur->l_fp;
  168.         return TRUE;
  169.     }
  170. #endif
  171.     cpos = 0;
  172.     if ((flag&EFNEW)!=0 || ttrow!=nrow-1) {
  173.         ttcolor(CTEXT);
  174.         ttmove(nrow-1, 0);
  175.         epresf = TRUE;
  176.     } else
  177.         eputc(' ');
  178.     eformat(fp, ap);
  179.     tteeol();
  180.     ttflush();
  181.     for (;;) {
  182.         c = getkey(FALSE);
  183.         if ((flag&EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) {
  184.             cpos += complt(flag, c, buf, cpos);
  185.             continue;
  186.         }
  187.         switch (c) {
  188.             case CCHR('J'):
  189.             c = CCHR('M');        /* and continue        */
  190.             case CCHR('M'):        /* Return, done.    */
  191.             if ((flag&EFFUNC) != 0) {
  192.                 if ((i = complt(flag, c, buf, cpos)) == 0)
  193.                     continue;
  194.                 if (i > 0) cpos += i;
  195.             }
  196.             buf[cpos] = '\0';
  197.             if ((flag&EFCR) != 0) {
  198.                 ttputc(CCHR('M'));
  199.                 ttflush();
  200.             }
  201. #ifndef NO_MACRO
  202.             if(macrodef) {
  203.                 LINE *lp;
  204.  
  205.                 if((lp = lalloc(cpos)) == NULL) return FALSE;
  206.                 lp->l_fp = maclcur->l_fp;
  207.                 maclcur->l_fp = lp;
  208.                 lp->l_bp = maclcur;
  209.                 maclcur = lp;
  210.                 bcopy(buf, lp->l_text, cpos);
  211.             }
  212. #endif
  213.             goto done;
  214.  
  215.             case CCHR('G'):        /* Bell, abort.        */
  216.             eputc(CCHR('G'));
  217.             (VOID) ctrlg(FFRAND, 0);
  218.             ttflush();
  219.             return ABORT;
  220.  
  221.             case CCHR('H'):
  222.             case CCHR('?'):        /* Rubout, erase.    */
  223.             if (cpos != 0) {
  224.                 ttputc('\b');
  225.                 ttputc(' ');
  226.                 ttputc('\b');
  227.                 --ttcol;
  228.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  229.                     ttputc('\b');
  230.                     ttputc(' ');
  231.                     ttputc('\b');
  232.                     --ttcol;
  233.                 }
  234.                 ttflush();
  235.             }
  236.             break;
  237.  
  238.             case CCHR('X'):        /* C-X            */
  239.             case CCHR('U'):        /* C-U, kill line.    */
  240.             while (cpos != 0) {
  241.                 ttputc('\b');
  242.                 ttputc(' ');
  243.                 ttputc('\b');
  244.                 --ttcol;
  245.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  246.                     ttputc('\b');
  247.                     ttputc(' ');
  248.                     ttputc('\b');
  249.                     --ttcol;
  250.                 }
  251.             }
  252.             ttflush();
  253.             break;
  254.  
  255.             case CCHR('W'):        /* C-W, kill to beginning of */
  256.                         /* previous word    */
  257.             /* back up to first word character or beginning */
  258.             while ((cpos > 0) && !ISWORD(buf[cpos - 1])) {
  259.                 ttputc('\b');
  260.                 ttputc(' ');
  261.                 ttputc('\b');
  262.                 --ttcol;
  263.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  264.                     ttputc('\b');
  265.                     ttputc(' ');
  266.                     ttputc('\b');
  267.                     --ttcol;
  268.                 }
  269.             }
  270.             while ((cpos > 0) && ISWORD(buf[cpos - 1])) {
  271.                 ttputc('\b');
  272.                 ttputc(' ');
  273.                 ttputc('\b');
  274.                 --ttcol;
  275.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  276.                     ttputc('\b');
  277.                     ttputc(' ');
  278.                     ttputc('\b');
  279.                     --ttcol;
  280.                 }
  281.             }
  282.             ttflush();
  283.             break;
  284.  
  285.             case CCHR('\\'):
  286.             case CCHR('Q'):        /* C-Q, quote next    */
  287.             c = getkey(FALSE);    /* and continue        */
  288.             default:            /* All the rest.    */
  289.             if (cpos < nbuf-1) {
  290.                 buf[cpos++] = (char) c;
  291.                 eputc((char) c);
  292.                 ttflush();
  293.             }
  294.         }
  295.     }
  296. done:    return buf[0] != '\0';
  297. }
  298.  
  299. /*
  300.  * do completion on a list of objects.
  301.  */
  302. static int complt(flags, c, buf, cpos)
  303. register char *buf;
  304. register int cpos;
  305. {
  306.     register LIST    *lh, *lh2;
  307.     int        i, nxtra;
  308.     int        nhits, bxtra;
  309.     int        wflag = FALSE;
  310.     int        msglen, nshown;
  311.     char        *msg;
  312.  
  313.     if ((flags&EFFUNC) != 0) {
  314.         buf[cpos] = '\0';
  315.         i = complete_function(buf, c);
  316.         if(i>0) {
  317.         eputs(&buf[cpos]);
  318.         ttflush();
  319.         return i;
  320.         }
  321.         switch(i) {
  322.         case -3:
  323.             msg = " [Ambiguous]";
  324.             break;
  325.         case -2:
  326.             i=0;
  327.             msg = " [No match]";
  328.             break;
  329.         case -1:
  330.         case 0:
  331.             return i;
  332.         default:
  333.             msg = " [Internal error]";
  334.             break;
  335.         }
  336.     } else {
  337.         if ((flags&EFBUF) != 0) lh = &(bheadp->b_list);
  338.         else panic("broken complt call: flags");
  339.  
  340.         if (c == ' ') wflag = TRUE;
  341.         else if (c != '\t' && c != CCHR('M')) panic("broken complt call: c");
  342.  
  343.         nhits = 0;
  344.         nxtra = HUGE;
  345.  
  346.         while (lh != NULL) {
  347.         for (i=0; i<cpos; ++i) {
  348.             if (buf[i] != lh->l_name[i])
  349.                 break;
  350.         }
  351.         if (i == cpos) {
  352.             if (nhits == 0)
  353.                 lh2 = lh;
  354.             ++nhits;
  355.             if (lh->l_name[i] == '\0') nxtra = -1;
  356.             else {
  357.                 bxtra = getxtra(lh, lh2, cpos, wflag);
  358.                 if (bxtra < nxtra) nxtra = bxtra;
  359.                 lh2 = lh;
  360.             }
  361.         }
  362.         lh = lh->l_next;
  363.         }
  364.         if (nhits == 0)
  365.         msg = " [No match]";
  366.         else if (nhits > 1 && nxtra == 0)
  367.         msg = " [Ambiguous]";
  368.         else {        /* Got a match, do it to it */
  369.         /*
  370.          * Being lazy - ought to check length, but all things
  371.          * autocompleted have known types/lengths.
  372.          */
  373.         if (nxtra < 0 && nhits > 1 && c == ' ') nxtra = 1;
  374.         for (i = 0; i < nxtra; ++i) {
  375.             buf[cpos] = lh2->l_name[cpos];
  376.             eputc(buf[cpos++]);
  377.         }
  378.         ttflush();
  379.         if (nxtra < 0 && c != CCHR('M')) return 0;
  380.         return nxtra;
  381.         }
  382.     }
  383.     /* Set up backspaces, etc., being mindful of echo line limit */
  384.     msglen = strlen(msg);
  385.     nshown = (ttcol + msglen + 2 > ncol) ?
  386.             ncol - ttcol - 2 : msglen;
  387.     eputs(msg);
  388.     sleep(1);
  389.     ttcol -= (i = nshown);        /* update ttcol!        */
  390.     while (i--)            /* move back before msg        */
  391.         ttputc('\b');
  392.     ttflush();            /* display to user        */
  393.     i = nshown;
  394.     while (i--)            /* blank out    on next flush    */
  395.         eputc(' ');
  396.     ttcol -= (i = nshown);        /* update ttcol on BS's        */
  397.     while (i--)
  398.         ttputc('\b');        /* update ttcol again!        */
  399.     return 0;
  400. }
  401.  
  402. /*
  403.  * The "lp1" and "lp2" point to list structures. The
  404.  * "cpos" is a horizontal position in the name.
  405.  * Return the longest block of characters that can be
  406.  * autocompleted at this point. Sometimes the two
  407.  * symbols are the same, but this is normal.
  408.   */
  409. getxtra(lp1, lp2, cpos, wflag) register LIST *lp1, *lp2; register int wflag; {
  410.     register int    i;
  411.  
  412.     i = cpos;
  413.     for (;;) {
  414.         if (lp1->l_name[i] != lp2->l_name[i]) break;
  415.         if (lp1->l_name[i] == '\0') break;
  416.         ++i;
  417.         if (wflag && !ISWORD(lp1->l_name[i-1])) break;
  418.     }
  419.     return (i - cpos);
  420. }
  421.  
  422. /*
  423.  * Special "printf" for the echo line.
  424.  * Each call to "ewprintf" starts a new line in the
  425.  * echo area, and ends with an erase to end of the
  426.  * echo line. The formatting is done by a call
  427.  * to the standard formatting routine.
  428.  */
  429. /*VARARGS 0 */
  430. VOID
  431. ewprintf(va_alist)
  432. va_dcl
  433. {
  434.     va_list pvar;
  435.     register char *fp;
  436.  
  437. #ifndef NO_MACRO
  438.     if(inmacro) return;
  439. #endif
  440.     va_start(pvar);
  441.     fp = va_arg(pvar, char *);
  442.     ttcolor(CTEXT);
  443.     ttmove(nrow-1, 0);
  444.     eformat(fp, &pvar);
  445.     va_end(pvar);
  446.     tteeol();
  447.     ttflush();
  448.     epresf = TRUE;
  449. }
  450.  
  451. /*
  452.  * Printf style formatting. This is
  453.  * called by both "ewprintf" and "ereply" to provide
  454.  * formatting services to their clients. The move to the
  455.  * start of the echo line, and the erase to the end of
  456.  * the echo line, is done by the caller.
  457.  * Note: %c works, and prints the "name" of the character.
  458.  * %k prints the name of a key (and takes no arguments).
  459.  */
  460. static VOID
  461. eformat(fp, ap)
  462. register char *fp;
  463. register va_list *ap;
  464. {
  465.     register int c;
  466.     char    kname[NKNAME];
  467.     char    *keyname();
  468.     char    *cp;
  469.  
  470.     while ((c = *fp++) != '\0') {
  471.         if (c != '%')
  472.             eputc(c);
  473.         else {
  474.             c = *fp++;
  475.             switch (c) {
  476.             case 'c':
  477.                 (VOID) keyname(kname, va_arg(*ap, int));
  478.                 eputs(kname);
  479.                 break;
  480.  
  481.             case 'k':
  482.                 cp = kname;
  483.                 for(c=0; c < key.k_count; c++) {
  484.                     cp = keyname(cp, key.k_chars[c]);
  485.                     *cp++ = ' ';
  486.                 }
  487.                 *--cp = '\0';
  488.                 eputs(kname);
  489.                 break;
  490.  
  491.             case 'd':
  492.                 eputi(va_arg(*ap, int), 10);
  493.                 break;
  494.  
  495.             case 'o':
  496.                 eputi(va_arg(*ap, int), 8);
  497.                 break;
  498.  
  499.             case 's':
  500.                 eputs(va_arg(*ap, char *));
  501.                 break;
  502.  
  503.             case 'l':/* explicit longword */
  504.                 c = *fp++;
  505.                 switch(c) {
  506.                 case 'd':
  507.                     eputl((long)va_arg(*ap, long), 10);
  508.                     break;
  509.                 default:
  510.                     eputc(c);
  511.                     break;
  512.                 }
  513.                 break;
  514.  
  515.             default:
  516.                 eputc(c);
  517.             }
  518.         }
  519.     }
  520. }
  521.  
  522. /*
  523.  * Put integer, in radix "r".
  524.  */
  525. static VOID
  526. eputi(i, r)
  527. register int i;
  528. register int r;
  529. {
  530.     register int    q;
  531.  
  532.     if(i<0) {
  533.         eputc('-');
  534.         i = -i;
  535.     }
  536.     if ((q=i/r) != 0)
  537.         eputi(q, r);
  538.     eputc(i%r+'0');
  539. }
  540.  
  541. /*
  542.  * Put long, in radix "r".
  543.  */
  544. static VOID
  545. eputl(l, r)
  546. register long l;
  547. register int  r;
  548. {
  549.     register long    q;
  550.  
  551.     if(l < 0) {
  552.         eputc('-');
  553.         l = -l;
  554.     }
  555.     if ((q=l/r) != 0)
  556.         eputl(q, r);
  557.     eputc((int)(l%r)+'0');
  558. }
  559.  
  560. /*
  561.  * Put string.
  562.  */
  563. static VOID
  564. eputs(s)
  565. register char *s;
  566. {
  567.     register int    c;
  568.  
  569.     while ((c = *s++) != '\0')
  570.         eputc(c);
  571. }
  572.  
  573. /*
  574.  * Put character. Watch for
  575.  * control characters, and for the line
  576.  * getting too long.
  577.  */
  578. static VOID
  579. eputc(c)
  580. register char c;
  581. {
  582.     if (ttcol+2 < ncol) {
  583.         if (ISCTRL(c)) {
  584.             eputc('^');
  585.             c = CCHR(c);
  586.         }
  587.         ttputc(c);
  588.         ++ttcol;
  589.     }
  590. }
  591.  
  592.